﻿using System;
using System.Collections;
using System.Configuration;
using System.DirectoryServices;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using Elmah;

namespace OrbitOne.Elmah
{
    public class O1XmlFileErrorLog : XmlFileErrorLog
    {
        [ThreadStatic]
        private static ErrorLog _defaultLog;

        public new static ErrorLog Default
        {
            get
            {
                if (_defaultLog == null)
                {

                    ErrorLog log;
                    IDictionary logConfiguration = ConfigurationSettings.GetConfig("OrbitOne.Elmah/errorLog") as IDictionary;
                    if (logConfiguration != null)
                    {
                        log = new O1XmlFileErrorLog(logConfiguration["LogPath"].ToString());
                    }
                    else
                    {
                        log = new MemoryErrorLog();
                    }
                    _defaultLog = log;
                }
                return _defaultLog;
            }
        }

        public override string ApplicationName
        {
            get
            {
                string websiteName = string.Empty;
                try
                {
                    websiteName = GetIISFriendlyApplicationName(HttpContext.Current.Request.ServerVariables["APPL_MD_PATH"], "localhost");
                }
                catch 
                {
                 //yum
                }
                return websiteName == string.Empty
                           ? string.Format("{0}{1}", HttpContext.Current.Request.Url.Host,
                                           HttpContext.Current.Request.ApplicationPath)
                                 .Trim("/".ToCharArray())
                           : websiteName;
            }
        }

        public O1XmlFileErrorLog(string logPath) : base(logPath) { }

        public O1XmlFileErrorLog(IDictionary config) : base(config) { }

        public string GetIISFriendlyApplicationName(string appMdPath, string host)
        {
            return GetIISFriendlyApplicationName(appMdPath, host, null, null);
        }

        public string GetIISFriendlyApplicationName(string appMdPath, string host, string userName, string password)
        {
            using (new ElevationManager())
            {
                if (appMdPath != null)
                {
                    Regex regex = new Regex(@"W3SVC/(\d+)/ROOT(/.+)*", RegexOptions.IgnoreCase);
                    Match match = regex.Match(appMdPath);
                    if (match.Success)
                    {
                        string virtualDirectory = string.Empty;
                        string siteId = match.Groups[1].ToString();
                        if (match.Groups.Count >= 3 && match.Groups[2].ToString() != string.Empty)
                        {
                            virtualDirectory = match.Groups[2].ToString();
                        }
                        DirectoryEntry w3svc = new DirectoryEntry(string.Format("IIS://{0}/W3SVC/{1}", host, siteId), userName, password);

                        return string.Format("{0}{1}", w3svc.Properties["ServerComment"][0], virtualDirectory).Trim('/');
                    }
                }
            }
            return string.Empty;
        }

        public override string Log(Error error)
        {
            string errorId = Guid.NewGuid().ToString();
            string timeStamp = DateTime.Now.ToString("yyyy-MM-ddHHmmssZ", CultureInfo.InvariantCulture);
            string path = Path.Combine(LogPath, string.Format(@"error-{0}-{1}.xml", timeStamp, errorId));
            XmlTextWriter writer = new XmlTextWriter(path, Encoding.UTF8);

            try
            {
                error.ApplicationName = ApplicationName;
                writer.Formatting = Formatting.Indented;
                writer.WriteStartElement("error");
                writer.WriteAttributeString("errorId", errorId);
                error.ToXml(writer);
                writer.WriteEndElement();
                writer.Flush();
            }
            finally
            {
                writer.Close();
            }

            return errorId;
        }
    }
}
